/*
 * Copyright 2009 (c) Patrick Pietens, braemarframework.org.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
package indigo.logger.publishers 
{	import indigo.logger.Logger;
	import indigo.utils.IDisposable;

	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.XMLSocket;
	import flash.utils.getTimer;
	/**	 * The Trazzle publisher is used by the Logger to send messages to the Trazzle debugger.	 *	 */	public class Trazzle implements IPublisher, IDisposable
	{
		/**
		 * Array with buffered messages. Buffered messages are send to the publisher when there wasn't a connection
		 */
		private var _buffer:Array = new Array;
		/**
		 * Socket that is used to communicate with the output
		 */		
		private var _socket:XMLSocket;

		
		/**
		 * Constructor
		 * 
		 */
		public function Trazzle():void
		{
			super( );
			this.initialize( );
		}

		
		/**
		 * Executes when the Trazzle is instantiated
		 * 
		 */
		private function initialize():void
		{
			// Create the socket
			this._socket = new XMLSocket;
			
			// Add listeners
			this._socket.addEventListener( Event.CONNECT, this.onConnect );
			this._socket.addEventListener( IOErrorEvent.IO_ERROR, this.onError );
			this._socket.addEventListener( SecurityErrorEvent.SECURITY_ERROR, this.onError );
			
			// Make a connection				
			this._socket.connect( "localhost", 3456 );				
		}		

		
		/**
		 * Executes when the socket succesfully established a connection
		 * @param	Event which triggers the method
		 * 
		 */
		private function onConnect( event:Event ):void
		{
			// Reverse the buffer
			this._buffer.reverse( );
			
			// Loop through all messages sending them to the output
			var i:int = this._buffer.length;
			while ( --i > -1 )
				this._socket.send( this._buffer[ i ] );
				
			// Empty buffer
			this._buffer = new Array;
		}

		
		/**
		 * Sends a message to the Trazzle
		 * @param 	Integer that indicates the message level
		 * @param 	String that indicates the path of the message (the class which sends the message)
		 * @param	String that indicates the title of the message
		 * @param	String that indicates the description of the message
		 * 
		 */
		public function sendMessage( level:int, path:String, title:*, message:* = null ):void
		{
			var myType:String = this.getType( level );
			var myMessage:XML = this.encodeMessage( myType, path, title.toString( ), message );
			
			// Send the message when there is a connection with Trazzle
			if ( this._socket.connected )
				this._socket.send( myMessage ); 
				
			// Otherwise store it in buffer
			else
				this._buffer.push( myMessage );
		}

		
		/**
		 * Clears the output of the publisher
		 * 
		 */		
		public function clearOutput():void
		{
			// Disabled		}

		
		/**
		 * Encodes the original message to Trazzle format
		 * @param 	Integer that indicates the message level
		 * @param 	String that indicates the path of the message (the class which sends the message)
		 * @param	String that indicates the title of the message
		 * @param	String that indicates the description of the message
		 * 
		 */
		private function getType( level:int ):String
		{
			var myType:String;
			switch ( level )
			{
				case Logger.LEVEL_INFO: 
					myType = "info"; 
					break;
				case Logger.LEVEL_LOG: 
					myType = "debug"; 
					break;
				case Logger.LEVEL_DEBUG: 
					myType = "debug"; 
					break;
				case Logger.LEVEL_ERROR: 
					myType = "error"; 
					break;
			}
			
			return myType;
		}

		
		/**
		 * Returns the message
		 * 
		 */
		private function encodeMessage( level:String, path:String, title:String, message:String ):XML
		{
			var myMessage:XML;
			var myTime:int = 0;
			var myCount:String = Logger.getInstance( ).messageCount.toString( );
			var myClass:String;
			var myMethod:String;
			
			var myParts:Array = path.split( "." );
			if ( myParts.length == 2 )
			{
				myClass = String( myParts[ 0 ] );
				myMethod = String( myParts[ 1 ] ).substr( 0, String( myParts[ 1 ] ).length - 2 );
			}
			else
				myClass = myMethod = String( myParts[ 0 ] ).substr( 0, String( myParts[ 0 ] ).length - 2 );
			
			if ( Logger.useTimestamp )
				myTime = getTimer( );
			
			// Send a fold message when the user sends a title and message
			myMessage = <log level={level} ts={myTime} line={myCount} class={myClass} method={myMethod} file="file" encodehtml={false}>
						<message>{title}</message>
					</log>;

			return myMessage;			
		}

		
		/**
		 * Executes when an error occured
		 * @param	Event which triggers the method
		 * 
		 */
		private function onError( event:Event ):void
		{
			// Do nothing
		}

		
		/**
		 * Unloads the output and disconnects the XMLSocket connection
		 * 
		 */
		public function dispose( event:Event = null ):void
		{
			// Close connection
			this._socket.close( );
			
			// Remove listeners
			this._socket.removeEventListener( Event.CONNECT, this.onConnect );
			this._socket.removeEventListener( IOErrorEvent.IO_ERROR, this.onError );
			this._socket.removeEventListener( SecurityErrorEvent.SECURITY_ERROR, this.onError );

			// Nullify properties
			this._socket = null;
			this._buffer = null;
		}
	}}